package top.kaoshanji.q1ch07c;

import top.kaoshanji.y1constant.FileConstant;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;

/**
 * 代码清单-q1ch07c-362页a：对映射文件中的部分加锁
 * author kaoshanji
 * ^_^
 * create time 2025/3/12 19:26
 */
public class LockingMappedFiles {

    static String pathStr = FileConstant.LOCAL_ROOT_PATH.concat("q1ch07c362页a\\test.dat");

    // 成员属性是可以在多个方法里使用
    // 只要在使用之前被初始化
    // 这说明成员属性是对象的状态

    static final int LENGTH = 0x8FFFFFF; // 128 MB
    static FileChannel fc;

    public static void main(String[] args) throws IOException {

        fc = new RandomAccessFile(pathStr, "rw").getChannel();
        MappedByteBuffer out = fc.map(FileChannel.MapMode.READ_WRITE, 0, LENGTH);

        for (int i = 0; i < LENGTH; i++) {
            out.put((byte)'x');
        }

        // 使用构造器创建对象
        // 通过构造器将外部的参数参数传进去
        new LockAndModify(out, 0, 0 + LENGTH/3);
        new LockAndModify(out, LENGTH/2, LENGTH/2 + LENGTH/4);

    }

    // 线程对象是通过构造器传递参数
    private static class LockAndModify extends Thread {

        private ByteBuffer buff;
        private int start, end;

        public LockAndModify(ByteBuffer mbb, int start, int end) {
            this.start = start;
            this.end = end;

            mbb.limit(end);
            mbb.position(start);

            buff = mbb.slice();
            start();
        }

        @Override
        public void run() {

            try {
                // 没有重叠部分的排他锁
                FileLock fl = fc.lock(start, end, false);
                System.out.println("Locked: "+ start +" to "+ end);

                // 执行修改
                while (buff.position() < buff.limit() - 1) {
                    buff.put((byte) (buff.get() + 1));
                }

                fl.release();
                System.out.println("Released: " + start + " to " + end);

            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }
    }





}
